;   This program is free software: you can redistribute it and/or modify
;   it under the terms of the GNU General Public License as published by
;   the Free Software Foundation， either version 3 of the License， or
;   (at your option) any later version.
;
;   This program is distributed in the hope that it will be useful，
;   but WITHOUT ANY WARRANTY; without even the implied warranty of
;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;   GNU General Public License for more details.
;
;   You should have received a copy of the GNU General Public License
;   along with this program.  If not， see <http://www.gnu.org/licenses/>.
;
;程序名称:4calc.asm
;功能:四则运算(10/16进制四则)
;环境:16BIT DOS实模式(windows/dos或dosbox)
;编译器:MASM 5.1-6X 
;用法:看说明
;返回值:没有
;破坏寄存器:不适用
;
;可计算10/16进制四则，平方和平方根。
;10进制，个数限制10个，范围(0-4294967295)，超过限制会印出overflow。
;16进制，个数限制8个， 范围(0-FFFFFFFF)。
;第１运算元输入后，可按＋－* /，或P或S (平方／平方根)。
;然后输入第２运算元，再按[＝]或[回车]，即时显示答案，显示最多18位。
;小数则显示最多20位。
;若在第１运算元时，按[空白]即时转换10进制和16进制。
;转制后仍可进行四则运算。
;若是16进制除，结果可能有小数，所以均以10进制显示
;
;注意1:这只是一个范例程式，具备最起码的功能，没有太花巧的技术。
;若你需要其他功能或加入或删减任何代码，请随便，但不能要求作者为你订制特定的功能或
;根据功课要求而改变这个子程序改变那个子程序，若是代码错误或优化代码的意见，
;则欢迎提出:)
;
;注意2:伸手党拿去取用没问题，但[不能]在代码任何位置或标题或程式上加上个人资料，
;例如作者谁谁谁，或者Written by XXX等等，这代码是本人的烂创作，不是谁或谁写的东西
;本人都不加名字了！
;
;没多少空闲，程序只加了一些简单解释，若要探入理解代码运作，
;请自行debug，不要问我，或要求增加注解。
;
;代码及程式
;http://pan.baidu.com/s/1pJxGSor
;4calc.txt（代码） 和4calc.exe是最后版本，包含所有功能
;4basic.txt（代码）和4calc.exe是较早版本，只包含10进制四则
;没有平方和平根，也没有即时转制，较适合伸手党，
;4basic.txt没有解释，可自行在4calc.txt或下面抄解释，不要烦我!
;
;----------------------------------------------------------------------
;常数设定
title1x     equ     0   
title1y     equ     0
title2x     equ     0
title2y     equ     18
max_dit     equ     10      ;十进位最大个数
max_hex     equ     8       ;十六进位最大个数
hexdec_space equ    27
dot_limit   equ     20      ;小数最大个数
Power_OP    equ     4       ;次方编号
SQ_OP       equ     5       ;平方根编号

.model small
.stack 100h
.data
title1      label   byte
db '----------------------------------------------',0dh,0ah
db '<<<<< Sample Four Fundamental Calculator >>>>>',0dh,0ah
db '______________________________________________','$'
title_L equ $ - offset title1
title2      label   byte
db ' X(+-*/)Y=Ans. Space=Hex/Dec, S=Squre, P=Power',0dh,0ah
db '----------------------------------------------','$'
title3      db '--- Hit a key to Continue,or ESC to quit ----','$'
title4      db title_L dup (20h),'$'
hex_str     db '__Hex(0-FFFFFFFF)$'
dec_str     db 'Dec(0-4294967295)$'
dec1_str    db '(Dec)$'
over_str    db 'Overflow !','$'
num1_buf    db max_dit * 4 dup (0)  ;第1运算元缓冲
num2_buf    db max_dit * 4 dup (0)  ;第2运算元缓冲

value_table label byte
Lo_value        dw      0
Hi_value        dw      0
current_Lo      dw      0 ;32bit第2运算元 
current_Hi      dw      0
prev_Lo         dw      0 ;32bit第1运算元
prev_Hi         dw      0
prev_op         dw      0
over_lo        dd	0 ;64 bit数低位
over_hi	    dd	0 ;64 bit数高位
num_count       dw	0
temp_count      dw      0
num1_count      dw      0 ;第1运算元个数
num2_count      dw      0 ;第2运算元个数
sign            dw      0 ;符号
sign1	          dw      0 ;第1运算元符号
operator        dw      0 ;运算子 + - * /
sign2	          dw      0 ;第2运算元符号
equal           dw      0
over            dw	0 ;溢位标志
temp_bp         dw      0 ;暂存bp值
op_proc         dw      0 ;finish 1 step,inc ..已有第一运算元标志
value_table_L   equ     $ - offset value_table
base_flag       db      0,0  ;进制标志
calc_line       db      title1y + 3
user_max_dit    dw      max_dit ;9
bhex_table      db      08,22,'084C2A6E195D3B7Fabcdef' ;max,comp lenght,data ;转制表
bhex_L          equ 	($ - offset bhex_table) - 2
hex_table       db      '0123456789ABCDEF'  ;十六进制表
op_table        db      '+-*/PS','=',0dh ;运算子
op_offset_table dw	offset Add_key  ;以下是各种运算子的子程序入口
                dw	offset Sub_key
                dw	offset Mul_key
                dw	offset Div_key
                dw	offset Power_key ;P
                dw	offset SQ_key ;S
                dw      offset Equ_key
                dw      offset Equ_key

;-------SQuare data --------------以下是平方根的变数(8087用)
ten             dd      10.0 
Dot_data        dd      0
status          dw      ?
integer         dd      ?
decimals        dd      ?
sq              dd      0 ;9876543         ;3142.6967 ^ 2     (0C46H.1B38H)   int 3143D
sq_str          db      'Square Root = $'
power_str       db      'The Power of 2 = $'
equal_str       db      20h,'=',20h,'$'
funct_table     label   byte
dw              offset  sq_str
dw              offset  power_str
;-------SQuare data end --------------
.code
START:
                MOV AX,@DATA ;取资料段
                MOV DS,AX
                mov es,ax
                call cls    ;清屏
next1:
                cld
                call init   ;变数初始化
                call print_box ;印出介面
                call set_oripos ;设定光标
                call print_dechex ;印出十/十六进制字符
                jc next2a  ;若有over则跳
                mov di,offset num1_buf ;第一运算元缓冲
                mov bx,offset op_table  ;第一运算元后容许的运算子: + - /  p s
                mov cx,6  ;+ / * / P S  ;6个
                call get_input ;读输入 ;读输入
                jc next2  ;若按esc,离开
                mov operator,ax ;存运算子 
                cmp ax,1   ;是第减号
                ja next1a  ; * or / ;减号以上运算子
                inc op_proc ; + or - ;设定已有第一运算元标志
next1a:
                mov num1_count,cx ;存第一运算元的个数
                mov sign1,dx ;存符号
                mov si,offset num1_buf ;第一运算元缓冲
                call tran  ;输入转换成数值
                jc next2a  ;错误印出over
                mov prev_Lo,ax  ;存32bit数值低位
                mov prev_Hi,dx  ;存32bit数值高位
                cmp operator,3  ;运算子是否3
                ja next3  ; P and S direct output ;若大于则是p或S,即平方或平方根,直接跳去求答案,不须输入第2运算元
                mov di,offset num2_buf ;第2运算元缓冲
                mov temp_count,0  ;设0
                mov bx,offset op_table + 6  ;第2运算元后容许的运算子 = 或 回车
                mov cx,2  ;2个
                call get_input ;读输入
next2:
                jc quit ;错误
                mov sign2,dx  ;存符号
                mov num2_count,cx  ;存第一运算元的个数
                mov si,offset num2_buf ;第2运算元缓冲
                call tran    ;输入转换成数值
                mov current_Lo,ax  ;存32bit数值低位
                mov current_Hi,dx ;存32bit数值高位
                cmp operator,3  ;是否除
                jnz next3 ;不是
                cmp current_Hi,0 ; 32bit数高位是否0
                jnz next3 ;不是
                cmp current_Lo,0 ; 32bit数低位是否0
                jnz next3 ;不是
next2a:
                mov dx,offset over_str  ;除数是0,印over
                mov ah,9
                int 21h
                jmp short next6
next3:          mov 	bx,operator  ;运算子
                shl	bx,1  ;调整
                mov     si,offset op_offset_table ;指向运算子的子程序进入点表格
                call    word ptr [si+bx]  ;呼叫子程序计算
                ; return EDX:EAX   ;返回值在EDX:EAX 的64bit数
                cmp 	operator,5 	;square ;运算子是否平方根
                jz 	next6  ;是
                cmp 	sign,0 ;符号 ?
                jz	next5 ;0,表示正则跳
                mov 	al,'-' ;1,表示负,印出[-]
                int 	29h
next5:		
                call  print_result ;根据 EDX:EAX的值印出结果
next6:		
                inc	calc_line  ;下一列
                cmp 	calc_line,title2y -1  ;是否到介面的最低列
                jbe	next7 ;未到
                mov 	calc_line,title1y + 3 ;后设光标回到介面顶
                call print_pause ;印出暂停
                mov ax,0c07h  ;读键
                int 	21h
                cmp 	al,1bh  ;ESC则离开
                jz	quit  ;走
                call	clear_line ;清除介面中所有资料
next7:          jmp	next1 ;回到起点
quit:
                mov     ah,4ch ;离开
                int     21h
;----------------------
init:  ;初始化子程序
                mov     al,0
                mov     di,offset value_table
                mov     cx,value_table_L
                rep     stosb
                ret
;----------------------
set_oripos: ;根据列号,设定光标子程序
                mov dl,title1x 
                mov dh,calc_line
                call setpos
                mov al,'>' ;print >
                int 29h
                ret
;----------------------
print_box: ;印出介面子程序
                mov dh,title1y 
                mov dl,title1x
                call setpos ;设定光标
                mov dx,offset title1
                mov ah,9
                int 21h
                mov bx,offset title2
print_bottom:
                mov dh,title2y 
                mov dl,title2x
print_str:
                call setpos
                mov dx,bx
                mov ah,9
                int 21h
                ret
;----------------------
print_pause: ;暂停子程序
                mov bx,offset title3
                call print_bottom 
                ret
;----------------------
clear_line:  ;清除列资料子程序
                mov cx,title2y - (title1y + 3)
                mov dh,calc_line
                mov dl,title1x 
clear10:
                push dx
                mov bx,offset title4
                call print_str
                pop dx
                inc dh
                loop clear10
                ret
;----------------------
; di = input buffer    ;运算元1和2的输入子程序
; bx = op table,cx = op count
get_input:
                mov bp,user_max_dit  ;取10/16进制最大输入个数
                mov sign,0  ;初始化符号
reinput:
                mov ax,0c07h ;clear buffer then read key ;清除键盘缓冲再读键
                int 21h
                cmp al,1bh ;esc 键
                jnz get7
                stc  ;enter 和  ESC离开
                ret
get7:
                cmp al,20h	;space 是否[空白]
                jnz get7a ;不是
                call base_key  ;做10/16进制即时转换	
                jmp short reinput ;再输入
get7a:
                cmp al,'-'  ;是否[-]
                jnz get10
                cmp op_proc,0  ;是否第一运算元,
                jnz reinput ;不是
                cmp bp,user_max_dit ;个数减值是否最大限制
                jnz get15 ;不是
                cmp sign,1 ;是否已有负
                jz reinput ;
get8:
                mov sign,1   ;设定负
                int 29h   ;印出 [-] 
                jmp short reinput 
get10:
                cmp al,8 ;是否backspace 
                jnz get15 ;不是
                cmp bp,user_max_dit ;个数减值是否最大限制
                jz reinput  ;不是,因为没有输入,最大限制仍未减值,不容许backspace
                call backspace ;模拟backspace 动作
                inc bp  ;加回
                dec di  ;退回前一个字节
                jmp short reinput
get15:
                cmp bp,user_max_dit ;个数减值是否最大限制
                jz get16  ;是
                call check_op  ;op in ax ;检查输入是否运算子
                jnc get20  ; 是运算子,准备离开
get16:
                cmp bp,0  ; 个数减值是否已是0,即已输入8或10个数
                jz reinput  ;是,不处理
                call read_char ;检查输入
                jc reinput  ;错误
                int 29h  ;印出输入数字 
                test base_flag,1 ;检查是否10或16进制 ,1 则16进制
                jnz get18  ;不是
                sub al,'0' ;10进制,ASCII转值
get18:
                stosb  ;存于缓冲区
                dec bp ;减个数减值 
                jmp reinput
get20:
                sub bp,user_max_dit ;个数减值 - 最大限制个数
                neg bp  ;补
                mov cx,bp ;得实际输入个数
                mov dx,sign ;存符号
                clc
                ret
;-------------------------
read_char: ;检查输入字符子程序 10进制是(0-9),16进制(0-f)
                push cx
                push di
                push bp
                test base_flag,1 ;10进制或16进制
                jz read_ch10  ;10进制
                mov cx,bhex_L ;16进制表格
                mov di,offset bhex_table + 2
                repne scasb ;是否0-F
                jnz read_ch40
                cmp al,'9' 
                jbe read_ch5 ;少或等于9
                and al,11011111b ;a-f转大写
read_ch5:
                clc
                jmp short read_ch50
read_ch10:
                cmp al,'0' ;是否0-9
                jb read_ch40
                cmp al,'9'
                jbe read_ch5 ;不是0-9,再输入
read_ch40:
                stc
read_ch50:
                pop bp
                pop di
                pop cx
                ret
;-------------------------
check_op:  ;检查运算子的子程序 (第1运算元是+-/ps)(第2运算元是=和回车)
                push bx
                push cx
                push dx
                mov dx,bx
ch_op10:
                mov ah,al
                and ah,11011111b ;upcase ;转大写
                cmp ah,'A' ;是否A-Z
                jb ch_op15
                cmp ah,'Z'
                ja ch_op15
                mov al,ah
ch_op15:
                cmp al,[bx]  ;比较是否运算子表格内的值,CX是个数
                jz ch_op20
                inc bx
                loop ch_op15
ch_op16:   ;not found
                stc  ;找不到,离开
                jmp short ch_op40
ch_op20:
                cmp al,'/' ;若是 /
                jnz ch_op22
                mov al,246 ; / 则转ascii除号
ch_op22:
                cmp al,'*'  ;若是 *
                jnz ch_op23
                mov al,'x' ; /   则转x

ch_op23:
                cmp al,20h ;base key ;是否按空白
                jnz ch_op24
                xor base_flag,1  ;10/16进制开关 ,按一空白10进制,再按一下16进制
                call change_base ;转换进制子程序
                jmp short ch_op16
ch_op24:
                cmp al,0dh ;是否回车
                jnz ch_op25
                mov al,'=' ;是转[=]号
ch_op25:
                sub bx,dx  ;减去偏移得运算子编号,如+ 为0,-为1...
                cmp bx,3  ;是否编号3 
                jbe ch_op30 ;+-*/  ;少于编号3则印出运算子,否则不印
                mov al,20h ;space mask P / S
ch_op30:
                int 29h
                mov ax,bx
                clc
ch_op40:
                pop dx
                pop cx
                pop bx
                ret
;-------------------------
getpos:  ;读光标位置
                mov bh,0
                mov ah,3
                int 10h
                ret
;----------------------
setpos: ;设定光标位置
                push bx
                mov bh,0
                mov ah,2
                int 10h
                pop bx
                ret
;----------------------
backspace: ;backspace模拟  ; cx=count
                mov dl,8
                mov ah,2
                int 21h
                mov dl,20h
                int 21h
                mov dl,8
                int 21h
                ret
;-----------------------------------------------------------
cls: ;清屏
                mov ah,0fh                  ;get display mode to al
                int 10h
                mov ah,0                    ;Set display mode
                int 10h
                ret
;-----------------------------------------------------------
;space key  ;按空白键子程序,转进制
Base_key:
                push 	ax
                push 	bx
                push 	cx
                push 	dx
                push 	si
                cmp op_proc,0   ; first num1 ;是否第1运算元
                jnz base30 	; no, second , quit ;不是,第2运算元不容许转进制,离开
                push cx
                push bp
                mov ax,user_max_dit ;old value  ;
                push ax  ;因为转进制,要保存之前的最大个数,如8和10
                mov al,base_flag  ;取新的进制标志
                mov base_flag+1,al ;old base flag ;保存
                xor base_flag,1  ;---------- toggle ;或进制标志,即1变0,0变1
                call print_dechex ;印出进制字符
                pop ax
                pop bp
                pop cx
                cmp bp,ax ; no input ? 已入个数是否是最大个数
                jnz base20 ;不是,即已有数值
                mov bp,user_max_dit ;BP=AX,即仍没有输入,直接离开
                jmp short base30
base20:
                call change_base ;转换进制子程序
base30:         pop	si
                pop	dx
                pop	cx
                pop	bx
                pop	ax
                ret
;-----------------------------------------------------------
Equ_key:
		ret
;-----------------------------------------------------------
print_dechex:  ;印出10/16进制字串子程序
                call getpos
                push dx
                mov dl,title1x + hexdec_space
                mov dh,title1y + 2
                call setpos
                mov dx,offset dec_str
                mov user_max_dit,max_dit  ;dec
                test base_flag,1
                jz base10
                mov user_max_dit,max_hex  ;hex
                mov dx,offset hex_str
base10:
                mov ah,9
                int 21h
                pop dx
                call setpos
                ret
;-----------------------------------------------------------
;bp,di will be change  ;转制子程序 (原理是用backspace删除己有输入,转制后,再模拟输入)
change_base:
;hex
; ax = user_max_dit
                sub bp,ax
                neg bp
                mov cx,bp ;取得已输入个数
change_10:
                push cx
                call backspace ;根据个数,删除己输入的数字
                pop cx
                loop change_10 
                mov cx,bp  ;取个数
                Xor ax,ax
                mov prev_Lo,ax ;清0
                mov prev_Hi,dx
                mov si,offset num1_buf ;第1运算元缓冲
                xor base_flag,1 ;转回之前的进制
                call tran ;计算第1运算元输入值
                xor base_flag,1 ;换回当前进制
                mov prev_Lo,ax ;保存 dx:ax
                mov prev_Hi,dx
                mov bp,user_max_dit ;取得新的个数限制
                mov temp_count,0
                mov 	di,offset num1_buf
                test base_flag,1 ;根据进制标志,决定转10进制还是16进制
                jz change_50
                mov Lo_value,ax
                mov Hi_value,dx
                call	disp_hex  ;把第1运算元的值转10进制显示
                jmp short change_60
change_50:
                mov bp,user_max_dit
                mov temp_bp,bp
                mov ax,prev_Lo
                mov dx,prev_Hi
                call out_dec ;把第1运算元的值转16进制显示
                mov bp,temp_bp
change_60:
                ret
;----------------------------------------------------------
disp_hex: ;输出16进制,实际上是模拟使用者输入16进制
                mov dx,Hi_value
                mov     bx,offset hex_table
                mov 	si,2
                ; dx = prev_hi			
change_15:
                mov     ch,4
change_20:
                mov     cl,4
                rol     dx,cl
                mov     al,dl
                and     al,00001111b
                xlatb
                cmp al,'0'
                jnz change_30
                cmp temp_count,0	;first
                jz	change_40
change_30:      stosb
                int 29h
                dec 	bp
                inc 	temp_count
change_40:
                dec     ch
                jnz     change_20
                mov dx,Lo_value
                dec	si
                jnz	change_15
                ret
;---------------------------------------------------
;input : dx-high ax-low  ;;输出10进制,实际上是模拟使用者输入10进制
;output : to screen
Out_dec:
                xor cx,cx
                xchg bp,dx
                mov si,10 ;div by 10
                mov bx,30h
out_dec1:
                or bp,bp
                jz out_dec3
                xchg bp,ax
                xor dx,dx
                div si
                xchg bp,ax
                div si
                or dl,bl
                push dx
                inc cx
                jmp short out_dec1
out_dec3:
                xor dx,dx
                div si
                or dl,bl
                push dx
                inc cx
                or ax,ax
                jnz out_dec3
out_dec4:
                pop ax
                int 29h
                inc temp_count
                dec temp_bp
                sub al,'0'
                stosb
                loop out_dec4
                ret
;--------------------------------
tran:  ;文字输入转换成真正值
                test base_flag,1 ;根据进制标志
                jz tran50
                ;hex
                call htoh ;文字16进制转值
                ret
tran50:
                ;dec
                call doth ;;文字10进制转值
                ret	
;--------------------------------
doth:  ;10进制文字转16进制值
; change dec input to hex
; input : si = offset of first byte
;         cx = no. of byte
; output: dx = Hi word
;         ax = Lo word
                push    bx
                push    cx
                push    bp
                xor     ax,ax
                mov     hi_value,ax
                mov     lo_value,ax
                xor     bp,bp                   ;clear bp
                mov     bx,10

tran1:          lodsb
                mov     ah,0
                mov     bp,ax                 ;store to bp
                mov     ax,hi_value           ;get hi_value
                mul     bx                    ;x 10
                jc      tran9                 ;is it large than ffff in dx
                mov     hi_value,ax           ;store to key hi
                mov     ax,bp                 ;restore from bp
                xchg    ax,lo_value           ;get key lo
                mul     bx                    ;x 10
                xchg    ax,lo_value           ;store to key lo
                add     lo_value,ax           ;add low byte to key lo
                add     hi_value,dx           ;add to key hi
                loop    tran1
                clc                           ;correct
                mov     dx,hi_value           ;get hi word
                mov     ax,lo_value           ;get lo word
                jmp     short tran10          ;exit
tran9:          stc                           ;incorrect
tran10:         pop     bp
                pop     cx
                pop     bx
                ret
;----------------------------------------------------------
;Lo_value        dw      0
;Hi_value        dw      0
; cx = count
htoh:  ;16进制文字转16进制值
;input  : offset of last string in si
;output : value in hi-lo buffer
                push 	bx
                push 	cx
                push 	si
                push 	di
                push 	bp
                xor	ax,ax
                mov 	Lo_value,ax
                mov 	Hi_value,ax
                xor     dx,dx
                mov     bx,cx		;8 ?
htoh10:         lodsb
                lea     di,bhex_table[2]       ;address of ascii_table
                mov     cx,16                 ;no.
                repne   scasb
                sub     di,(offset bhex_table[2])+1   ;adjust position
                mov     cx,4
htoh20:         shr     di,1                  ;shift right side to carry
                rcl     Lo_value,1            ;shift carry to right side
                rcl     Hi_value,1            ;shift carry to right side
                loop    htoh20
                dec     bx
                jnz     htoh10
                mov     ax,Lo_value            ;shift carry to right side
                mov 	dx,Hi_value           ;shift carry to right side
                pop 	bp
                pop	di
                pop	si
                pop	cx
                pop	bx
                ret
;------------------------------------------------------------------------------
;mov eax, over_lo  ;印出64bit结果
;mov edx,over_hi

.386  ;动用32BIT暂存器
print_result:
                test base_flag,1 ; 根据进制标志印出10或16进制
                jz 	print_re30
                cmp     operator,3      ;div then print dec;是否除
                jz      print_re30  ;除则10/16进制都印出10制,因为有小数
                mov     eax,over_hi
                mov 	cl,16
                mov 	edx,eax
                shr 	edx,cl
                and 	eax,0000FFFFh		
                mov Lo_value,ax
                mov Hi_value,dx
                call	disp_hex
                mov 	eax,over_lo
                mov 	cl,16
                mov 	edx,eax
                shr 	edx,cl
                and 	eax,0000FFFFh		
                mov Lo_value,ax
                mov Hi_value,dx
                call	disp_hex
                ret
print_re30:     call    print_dec
                cmp     operator,3      ;div then print dec ;是否除
		jnz	print_re40        ;不是
                test    base_flag,1 ;是否16进制
                jz      print_re40 ;不是
                mov     dx,offset dec1_str ;印出(dec)
		mov	ah,9
		int	21h
print_re40:	ret
;------------------------------------------------------------------------------
;.386  ;加法子程序
Add_key:
            mov 	sign,0
		xor	edx,edx
		mov	eax,dword ptr prev_lo
		mov 	ebx,dword ptr current_lo
		xor	ecx,ecx
		mov 	cx,sign1
		add	cx,operator ;0 or 1,+  or -
		test	ecx,1
		jz	add10
		cmp 	eax,ebx
		jae	add5
		xchg	eax,ebx
		mov 	cx,sign1
		xchg 	cx,sign2
		xchg 	cx,sign1

add5:		sub	eax,ebx
		cmp 	sign1,0
		jz	addx
		mov 	sign,1
		jmp 	short addx
		ret		

add10:		add	eax,ebx
		adc	edx,0
		cmp 	ecx,0
		jz	addx
		cmp 	cx,2
		jnz	addx
		mov 	sign,1
addx:           mov 	over_lo,eax
	        mov 	over_hi,edx
		ret
;-----------------------------------------------------------
Sub_key:	mov 	sign,0     ;减法子程序
           or	edx,edx
            mov	eax,dword ptr prev_lo
		mov 	ebx,dword ptr current_lo
		cmp 	sign1,0
		jz	sub10
		add 	eax,ebx
		adc 	edx,0
		mov 	sign,1
		jmp	short subx
sub10:	sub	eax,ebx
		jnc	subx
		mov 	sign,1
		neg	eax	
subx:           
		mov 	over_hi,edx
		mov 	over_lo,eax
            ret
;-----------------------------------------------------------
Mul_key:	;乘法子程序
		mov 	sign,0        
		push    ecx
		mov 	eax,dword ptr current_lo
		mov 	ebx,dword ptr prev_lo
		xor	edx,edx
		call	test_sign
		mul	ebx
		test	ecx,1
		jz	mul10
		mov 	sign,1
mul10:	mov 	over_lo,eax
		mov	over_hi,edx
		pop     ecx
            ret
;-----------------------------------------------------------
Div_key:  ;除法子程序
; dx:ax / cx:bx = ?
; return dx:ax
		mov 	sign,0
		mov 	eax,dword ptr prev_lo		
		mov 	ebx,dword ptr current_lo
		xor	edx,edx
		call	test_sign
		div	ebx
		test	ecx,1
		jz	div40
		mov 	sign,1
div40:		mov	over_hi,edx
		mov 	over_lo,eax
		mov 	edx,0
            ret
;-----------------------------------------------------------
test_sign:	;检查符号子程序
		xor	ecx,ecx
		test 	sign1,1
		jz	test_s10
		xor 	ecx,1
test_s10:	test	sign2,1
		jz	test_s20
		xor 	ecx,1
test_s20:	
		ret
;-----------------------------------------------------------
;印出64bit结果
print_dec: 
            mov eax,over_lo
            mov edx,over_hi
            cmp operator,3
            Jnz print_dec0 	
            xor edx,edx
print_dec0:
            xor ecx,ecx
            xchg ebp,edx
            mov esi,10 ;div by 10
            mov ebx,30h
print_dec1:
            or ebp,ebp
            jz print_dec3
            xchg ebp,eax
            xor edx,edx
            div esi
            xchg ebp,eax
            div esi
            or dl,bl
            push dx
            inc ecx
            jmp short print_dec1
print_dec3: 
            xor edx,edx
            div esi
            or dl,bl
            push dx
            inc ecx
            or eax,eax
            Jnz print_dec3
print_dec4:
            pop ax
            int 29h
            loop print_dec4
            cmp operator,3 ;是否除,若是,须印小数
            jnz print_dec7
            cmp  over_hi,0
            jz print_dec7
            mov al,'.'
            int 29h
            mov eax,over_hi
            mov ebx,10
            mov ecx,dot_limit ;20 位小数
            xor edx,edx
print_dec5:
            mul ebx
            xor edx,edx
            div dword ptr current_lo
            or al,30h
            int 29h
            mov eax,edx
            or edx,edx
            jz print_dec7
            loop print_dec5
print_dec7:
            ret
;-----------------------
Power_key:  ;平方子程序
            mov al,253  ;^
            int 29h
            mov dx,offset equal_str
            mov ah,9
            int 21h
            mov eax,dword ptr prev_lo
            mov ebx,eax
            mul ebx
            mov over_hi,edx
            mov over_lo,eax
            mov sign,0 ;reset
            ret
;-----------------------
SQ_key:  ;平方根子程序 (利用80387代码)
            cmp sign1,0
            jz SQ_10
            mov al,'='
            int 29h
            mov dx,offset over_str
            mov ah,9
            int 21h
            stc
            ret
SQ_10:
            mov eax,dword ptr prev_lo
            mov sq,eax
            mov al,251  ;square 
            int 29h
            mov dx,offset equal_str
            mov ah,9
            int 21h
            call square
            ret
;--------------------
.387  ;80387代码
;--------------------
square:
            finit    
            fild dword ptr sq  ; load int
            ; fld dword ptr dot_data ; load int
            fsqrt ;  get sqrt !
            fstp dot_data ;save
            fstcw status	 
            or status,0c00h
            fldcw status
            fld dot_data
            ftst			
            fstsw ax
            and ax,4500h
            cmp ax,0100h
            jnz positive
            mov al,'-'
            int 29h
            fabs		
positive:
            fld st	
            frndint         
            fist integer 
            fsubr            
            fabs
            fstp decimals    
            mov eax,integer
            mov ebx,10
            mov cx,0
again1:
            mov edx,0
            div ebx
            add dl,30h
            push dx
            inc cx
            cmp eax,0
            jnz again1
disp1:
            pop ax
            int 29h
            loop disp1
            mov al,'.'
            int 29h
            mov eax,decimals
            fstcw status
            xor status,0c00h
            fldcw status
            fld decimals
            fxtract
            fstp decimals
            fabs
            fistp integer
            mov ecx,integer
            mov eax,decimals
            shl eax,9
            rcr eax,cl
again2:
            mul ebx
            push eax
            xchg eax,edx
            add al,30h
            int 29h
            pop eax
            cmp eax,0
            jnz again2
            ret
;--------

END START